/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.j2objc.jdt;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.devtools.j2objc.ast.AbstractTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotatableType;
import com.google.devtools.j2objc.ast.Annotation;
import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotationTypeMemberDeclaration;
import com.google.devtools.j2objc.ast.ArrayAccess;
import com.google.devtools.j2objc.ast.ArrayCreation;
import com.google.devtools.j2objc.ast.ArrayInitializer;
import com.google.devtools.j2objc.ast.ArrayType;
import com.google.devtools.j2objc.ast.AssertStatement;
import com.google.devtools.j2objc.ast.Assignment;
import com.google.devtools.j2objc.ast.Block;
import com.google.devtools.j2objc.ast.BlockComment;
import com.google.devtools.j2objc.ast.BodyDeclaration;
import com.google.devtools.j2objc.ast.BooleanLiteral;
import com.google.devtools.j2objc.ast.BreakStatement;
import com.google.devtools.j2objc.ast.CastExpression;
import com.google.devtools.j2objc.ast.CatchClause;
import com.google.devtools.j2objc.ast.CharacterLiteral;
import com.google.devtools.j2objc.ast.ClassInstanceCreation;
import com.google.devtools.j2objc.ast.Comment;
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.ConditionalExpression;
import com.google.devtools.j2objc.ast.ConstructorInvocation;
import com.google.devtools.j2objc.ast.ContinueStatement;
import com.google.devtools.j2objc.ast.CreationReference;
import com.google.devtools.j2objc.ast.Dimension;
import com.google.devtools.j2objc.ast.DoStatement;
import com.google.devtools.j2objc.ast.EmptyStatement;
import com.google.devtools.j2objc.ast.EnhancedForStatement;
import com.google.devtools.j2objc.ast.EnumConstantDeclaration;
import com.google.devtools.j2objc.ast.EnumDeclaration;
import com.google.devtools.j2objc.ast.Expression;
import com.google.devtools.j2objc.ast.ExpressionMethodReference;
import com.google.devtools.j2objc.ast.ExpressionStatement;
import com.google.devtools.j2objc.ast.FieldAccess;
import com.google.devtools.j2objc.ast.FieldDeclaration;
import com.google.devtools.j2objc.ast.ForStatement;
import com.google.devtools.j2objc.ast.FunctionalExpression;
import com.google.devtools.j2objc.ast.IfStatement;
import com.google.devtools.j2objc.ast.InfixExpression;
import com.google.devtools.j2objc.ast.Initializer;
import com.google.devtools.j2objc.ast.InstanceofExpression;
import com.google.devtools.j2objc.ast.IntersectionType;
import com.google.devtools.j2objc.ast.Javadoc;
import com.google.devtools.j2objc.ast.LabeledStatement;
import com.google.devtools.j2objc.ast.LambdaExpression;
import com.google.devtools.j2objc.ast.LineComment;
import com.google.devtools.j2objc.ast.MarkerAnnotation;
import com.google.devtools.j2objc.ast.MemberValuePair;
import com.google.devtools.j2objc.ast.MethodDeclaration;
import com.google.devtools.j2objc.ast.MethodInvocation;
import com.google.devtools.j2objc.ast.MethodReference;
import com.google.devtools.j2objc.ast.Name;
import com.google.devtools.j2objc.ast.NameQualifiedType;
import com.google.devtools.j2objc.ast.NormalAnnotation;
import com.google.devtools.j2objc.ast.NullLiteral;
import com.google.devtools.j2objc.ast.NumberLiteral;
import com.google.devtools.j2objc.ast.PackageDeclaration;
import com.google.devtools.j2objc.ast.ParameterizedType;
import com.google.devtools.j2objc.ast.ParenthesizedExpression;
import com.google.devtools.j2objc.ast.PostfixExpression;
import com.google.devtools.j2objc.ast.PrefixExpression;
import com.google.devtools.j2objc.ast.PrimitiveType;
import com.google.devtools.j2objc.ast.PropertyAnnotation;
import com.google.devtools.j2objc.ast.QualifiedName;
import com.google.devtools.j2objc.ast.QualifiedType;
import com.google.devtools.j2objc.ast.ReturnStatement;
import com.google.devtools.j2objc.ast.SimpleName;
import com.google.devtools.j2objc.ast.SimpleType;
import com.google.devtools.j2objc.ast.SingleMemberAnnotation;
import com.google.devtools.j2objc.ast.SingleVariableDeclaration;
import com.google.devtools.j2objc.ast.SourcePosition;
import com.google.devtools.j2objc.ast.Statement;
import com.google.devtools.j2objc.ast.StringLiteral;
import com.google.devtools.j2objc.ast.SuperConstructorInvocation;
import com.google.devtools.j2objc.ast.SuperFieldAccess;
import com.google.devtools.j2objc.ast.SuperMethodInvocation;
import com.google.devtools.j2objc.ast.SuperMethodReference;
import com.google.devtools.j2objc.ast.SwitchCase;
import com.google.devtools.j2objc.ast.SwitchStatement;
import com.google.devtools.j2objc.ast.SynchronizedStatement;
import com.google.devtools.j2objc.ast.TagElement;
import com.google.devtools.j2objc.ast.TagElement.TagKind;
import com.google.devtools.j2objc.ast.TextElement;
import com.google.devtools.j2objc.ast.ThisExpression;
import com.google.devtools.j2objc.ast.ThrowStatement;
import com.google.devtools.j2objc.ast.TreeNode;
import com.google.devtools.j2objc.ast.TryStatement;
import com.google.devtools.j2objc.ast.Type;
import com.google.devtools.j2objc.ast.TypeDeclaration;
import com.google.devtools.j2objc.ast.TypeDeclarationStatement;
import com.google.devtools.j2objc.ast.TypeLiteral;
import com.google.devtools.j2objc.ast.TypeMethodReference;
import com.google.devtools.j2objc.ast.UnionType;
import com.google.devtools.j2objc.ast.VariableDeclaration;
import com.google.devtools.j2objc.ast.VariableDeclarationExpression;
import com.google.devtools.j2objc.ast.VariableDeclarationFragment;
import com.google.devtools.j2objc.ast.VariableDeclarationStatement;
import com.google.devtools.j2objc.ast.WhileStatement;
import com.google.devtools.j2objc.types.ExecutablePair;
import com.google.devtools.j2objc.types.GeneratedVariableElement;
import com.google.devtools.j2objc.util.BindingUtil;
import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.TranslationEnvironment;
import com.google.devtools.j2objc.util.TypeUtil;
import com.google.j2objc.annotations.Property;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
/**
* Converts a Java AST from the JDT data structure to our J2ObjC data structure.
*/
public class TreeConverter {
public static CompilationUnit convertCompilationUnit(
TranslationEnvironment env, org.eclipse.jdt.core.dom.CompilationUnit jdtUnit,
String sourceFilePath, String mainTypeName, String source) {
CompilationUnit unit = new CompilationUnit(env, sourceFilePath, mainTypeName, source);
if (jdtUnit.getPackage() == null) {
unit.setPackage(new PackageDeclaration());
} else {
unit.setPackage((PackageDeclaration) TreeConverter.convert(jdtUnit.getPackage()));
}
for (Object comment : jdtUnit.getCommentList()) {
// Comments are not normally parented in the JDT AST. Javadoc nodes are
// normally parented by the BodyDeclaration they apply to, so here we only
// keep the unparented comments to avoid duplicate comment nodes.
ASTNode commentParent = ((ASTNode) comment).getParent();
if (commentParent == null || commentParent.equals(jdtUnit)) {
Comment newComment = (Comment) TreeConverter.convert(comment);
// Since the comment is unparented, it's constructor is unable to get
// the root CompilationUnit to determine the line number.
newComment.setLineNumber(jdtUnit.getLineNumber(newComment.getStartPosition()));
unit.addComment(newComment);
}
}
for (Object type : jdtUnit.types()) {
unit.addType((AbstractTypeDeclaration) TreeConverter.convert(type));
}
return unit;
}
public static Statement convertStatement(org.eclipse.jdt.core.dom.Statement jdtStatement) {
return (Statement) convert(jdtStatement);
}
public static TreeNode convert(Object obj) {
if (obj == null) {
return null;
}
ASTNode jdtNode = (ASTNode) obj;
TreeNode node = convertInner(jdtNode)
.setPosition(getPosition(jdtNode));
node.validate();
return node;
}
private static SourcePosition getPosition(ASTNode jdtNode) {
int startPosition = jdtNode.getStartPosition();
int length = jdtNode.getLength();
ASTNode root = jdtNode.getRoot();
if (root instanceof org.eclipse.jdt.core.dom.CompilationUnit) {
int line = ((org.eclipse.jdt.core.dom.CompilationUnit) root).getLineNumber(startPosition);
return new SourcePosition(startPosition, length, line);
} else {
return new SourcePosition(startPosition, length);
}
}
private static TreeNode convertInner(ASTNode jdtNode) {
switch (jdtNode.getNodeType()) {
case ASTNode.ANNOTATION_TYPE_DECLARATION:
return convertAnnotationTypeDeclaration(
(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) jdtNode);
case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
return convertAnnotationTypeMemberDeclaration(
(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration) jdtNode);
case ASTNode.ARRAY_ACCESS:
return convertArrayAccess((org.eclipse.jdt.core.dom.ArrayAccess) jdtNode);
case ASTNode.ARRAY_CREATION:
return convertArrayCreation((org.eclipse.jdt.core.dom.ArrayCreation) jdtNode);
case ASTNode.ARRAY_INITIALIZER:
return convertArrayInitializer((org.eclipse.jdt.core.dom.ArrayInitializer) jdtNode);
case ASTNode.ARRAY_TYPE:
return convertArrayType((org.eclipse.jdt.core.dom.ArrayType) jdtNode);
case ASTNode.ASSERT_STATEMENT:
return convertAssertStatement((org.eclipse.jdt.core.dom.AssertStatement) jdtNode);
case ASTNode.ASSIGNMENT:
return convertAssignment((org.eclipse.jdt.core.dom.Assignment) jdtNode);
case ASTNode.BLOCK:
return convertBlock((org.eclipse.jdt.core.dom.Block) jdtNode);
case ASTNode.BLOCK_COMMENT:
return new BlockComment();
case ASTNode.BOOLEAN_LITERAL:
return convertBooleanLiteral((org.eclipse.jdt.core.dom.BooleanLiteral) jdtNode);
case ASTNode.BREAK_STATEMENT:
return convertBreakStatement((org.eclipse.jdt.core.dom.BreakStatement) jdtNode);
case ASTNode.CAST_EXPRESSION:
return convertCastExpression((org.eclipse.jdt.core.dom.CastExpression) jdtNode);
case ASTNode.CATCH_CLAUSE:
return convertCatchClause((org.eclipse.jdt.core.dom.CatchClause) jdtNode);
case ASTNode.CHARACTER_LITERAL:
return convertCharacterLiteral((org.eclipse.jdt.core.dom.CharacterLiteral) jdtNode);
case ASTNode.CLASS_INSTANCE_CREATION:
return convertClassInstanceCreation(
(org.eclipse.jdt.core.dom.ClassInstanceCreation) jdtNode);
case ASTNode.CONDITIONAL_EXPRESSION:
return convertConditionalExpression(
(org.eclipse.jdt.core.dom.ConditionalExpression) jdtNode);
case ASTNode.CONSTRUCTOR_INVOCATION:
return convertConstructorInvocation(
(org.eclipse.jdt.core.dom.ConstructorInvocation) jdtNode);
case ASTNode.CONTINUE_STATEMENT:
return convertContinueStatement((org.eclipse.jdt.core.dom.ContinueStatement) jdtNode);
case ASTNode.CREATION_REFERENCE:
return convertCreationReference((org.eclipse.jdt.core.dom.CreationReference) jdtNode);
case ASTNode.DIMENSION:
return convertDimension((org.eclipse.jdt.core.dom.Dimension) jdtNode);
case ASTNode.DO_STATEMENT:
return convertDoStatement((org.eclipse.jdt.core.dom.DoStatement) jdtNode);
case ASTNode.EMPTY_STATEMENT:
return new EmptyStatement();
case ASTNode.ENHANCED_FOR_STATEMENT:
return convertEnhancedForStatement((org.eclipse.jdt.core.dom.EnhancedForStatement) jdtNode);
case ASTNode.ENUM_CONSTANT_DECLARATION:
return convertEnumConstantDeclaration(
(org.eclipse.jdt.core.dom.EnumConstantDeclaration) jdtNode);
case ASTNode.ENUM_DECLARATION:
return convertEnumDeclaration((org.eclipse.jdt.core.dom.EnumDeclaration) jdtNode);
case ASTNode.EXPRESSION_METHOD_REFERENCE:
return convertExpressionMethodReference(
(org.eclipse.jdt.core.dom.ExpressionMethodReference) jdtNode);
case ASTNode.EXPRESSION_STATEMENT:
return convertExpressionStatement((org.eclipse.jdt.core.dom.ExpressionStatement) jdtNode);
case ASTNode.FIELD_ACCESS:
return convertFieldAccess((org.eclipse.jdt.core.dom.FieldAccess) jdtNode);
case ASTNode.FIELD_DECLARATION:
return convertFieldDeclaration((org.eclipse.jdt.core.dom.FieldDeclaration) jdtNode);
case ASTNode.FOR_STATEMENT:
return convertForStatement((org.eclipse.jdt.core.dom.ForStatement) jdtNode);
case ASTNode.IF_STATEMENT:
return convertIfStatement((org.eclipse.jdt.core.dom.IfStatement) jdtNode);
case ASTNode.INFIX_EXPRESSION:
return convertInfixExpression((org.eclipse.jdt.core.dom.InfixExpression) jdtNode);
case ASTNode.INTERSECTION_TYPE:
return convertIntersectionType((org.eclipse.jdt.core.dom.IntersectionType) jdtNode);
case ASTNode.INITIALIZER:
return convertInitializer((org.eclipse.jdt.core.dom.Initializer) jdtNode);
case ASTNode.INSTANCEOF_EXPRESSION:
return convertInstanceofExpression((org.eclipse.jdt.core.dom.InstanceofExpression) jdtNode);
case ASTNode.JAVADOC:
return convertJavadoc((org.eclipse.jdt.core.dom.Javadoc) jdtNode);
case ASTNode.LABELED_STATEMENT:
return convertLabeledStatement((org.eclipse.jdt.core.dom.LabeledStatement) jdtNode);
case ASTNode.LAMBDA_EXPRESSION:
return convertLambdaExpression((org.eclipse.jdt.core.dom.LambdaExpression) jdtNode);
case ASTNode.LINE_COMMENT:
return new LineComment();
case ASTNode.MARKER_ANNOTATION:
return convertMarkerAnnotation((org.eclipse.jdt.core.dom.MarkerAnnotation) jdtNode);
case ASTNode.MEMBER_VALUE_PAIR:
return convertMemberValuePair((org.eclipse.jdt.core.dom.MemberValuePair) jdtNode);
case ASTNode.METHOD_DECLARATION:
return convertMethodDeclaration((org.eclipse.jdt.core.dom.MethodDeclaration) jdtNode);
case ASTNode.METHOD_INVOCATION:
return convertMethodInvocation((org.eclipse.jdt.core.dom.MethodInvocation) jdtNode);
case ASTNode.NAME_QUALIFIED_TYPE:
return convertNameQualifiedType((org.eclipse.jdt.core.dom.NameQualifiedType) jdtNode);
case ASTNode.NORMAL_ANNOTATION:
return convertNormalAnnotation((org.eclipse.jdt.core.dom.NormalAnnotation) jdtNode);
case ASTNode.NULL_LITERAL:
return new NullLiteral(BindingConverter.NULL_TYPE);
case ASTNode.NUMBER_LITERAL:
return convertNumberLiteral((org.eclipse.jdt.core.dom.NumberLiteral) jdtNode);
case ASTNode.PACKAGE_DECLARATION:
return convertPackageDeclaration((org.eclipse.jdt.core.dom.PackageDeclaration) jdtNode);
case ASTNode.PARAMETERIZED_TYPE:
return convertParameterizedType((org.eclipse.jdt.core.dom.ParameterizedType) jdtNode);
case ASTNode.PARENTHESIZED_EXPRESSION:
return convertParenthesizedExpression(
(org.eclipse.jdt.core.dom.ParenthesizedExpression) jdtNode);
case ASTNode.POSTFIX_EXPRESSION:
return convertPostfixExpression((org.eclipse.jdt.core.dom.PostfixExpression) jdtNode);
case ASTNode.PREFIX_EXPRESSION:
return convertPrefixExpression((org.eclipse.jdt.core.dom.PrefixExpression) jdtNode);
case ASTNode.PRIMITIVE_TYPE:
return convertPrimitiveType((org.eclipse.jdt.core.dom.PrimitiveType) jdtNode);
case ASTNode.QUALIFIED_NAME:
return convertQualifiedName((org.eclipse.jdt.core.dom.QualifiedName) jdtNode);
case ASTNode.QUALIFIED_TYPE:
return convertQualifiedType((org.eclipse.jdt.core.dom.QualifiedType) jdtNode);
case ASTNode.RETURN_STATEMENT:
return convertReturnStatement((org.eclipse.jdt.core.dom.ReturnStatement) jdtNode);
case ASTNode.SIMPLE_NAME:
return convertSimpleName((org.eclipse.jdt.core.dom.SimpleName) jdtNode);
case ASTNode.SIMPLE_TYPE:
return convertSimpleType((org.eclipse.jdt.core.dom.SimpleType) jdtNode);
case ASTNode.SINGLE_MEMBER_ANNOTATION:
return convertSingleMemberAnnotation(
(org.eclipse.jdt.core.dom.SingleMemberAnnotation) jdtNode);
case ASTNode.SINGLE_VARIABLE_DECLARATION:
return convertSingleVariableDeclaration(
(org.eclipse.jdt.core.dom.SingleVariableDeclaration) jdtNode);
case ASTNode.STRING_LITERAL:
return convertStringLiteral((org.eclipse.jdt.core.dom.StringLiteral) jdtNode);
case ASTNode.SUPER_CONSTRUCTOR_INVOCATION:
return convertSuperConstructorInvocation(
(org.eclipse.jdt.core.dom.SuperConstructorInvocation) jdtNode);
case ASTNode.SUPER_FIELD_ACCESS:
return convertSuperFieldAccess((org.eclipse.jdt.core.dom.SuperFieldAccess) jdtNode);
case ASTNode.SUPER_METHOD_INVOCATION:
return convertSuperMethodInvocation(
(org.eclipse.jdt.core.dom.SuperMethodInvocation) jdtNode);
case ASTNode.SUPER_METHOD_REFERENCE:
return convertSuperMethodReference((org.eclipse.jdt.core.dom.SuperMethodReference) jdtNode);
case ASTNode.SWITCH_CASE:
return convertSwitchCase((org.eclipse.jdt.core.dom.SwitchCase) jdtNode);
case ASTNode.SWITCH_STATEMENT:
return convertSwitchStatement((org.eclipse.jdt.core.dom.SwitchStatement) jdtNode);
case ASTNode.SYNCHRONIZED_STATEMENT:
return convertSynchronizedStatement(
(org.eclipse.jdt.core.dom.SynchronizedStatement) jdtNode);
case ASTNode.TAG_ELEMENT:
return convertTagElement((org.eclipse.jdt.core.dom.TagElement) jdtNode);
case ASTNode.TEXT_ELEMENT:
return convertTextElement(((org.eclipse.jdt.core.dom.TextElement) jdtNode).getText());
case ASTNode.THIS_EXPRESSION:
return convertThisExpression((org.eclipse.jdt.core.dom.ThisExpression) jdtNode);
case ASTNode.THROW_STATEMENT:
return convertThrowStatement((org.eclipse.jdt.core.dom.ThrowStatement) jdtNode);
case ASTNode.TRY_STATEMENT:
return convertTryStatement((org.eclipse.jdt.core.dom.TryStatement) jdtNode);
case ASTNode.TYPE_DECLARATION:
return convertTypeDeclaration((org.eclipse.jdt.core.dom.TypeDeclaration) jdtNode);
case ASTNode.TYPE_DECLARATION_STATEMENT:
return convertTypeDeclarationStatement(
(org.eclipse.jdt.core.dom.TypeDeclarationStatement) jdtNode);
case ASTNode.TYPE_LITERAL:
return convertTypeLiteral((org.eclipse.jdt.core.dom.TypeLiteral) jdtNode);
case ASTNode.TYPE_METHOD_REFERENCE:
return convertTypeMethodReference((org.eclipse.jdt.core.dom.TypeMethodReference) jdtNode);
case ASTNode.UNION_TYPE:
return convertUnionType((org.eclipse.jdt.core.dom.UnionType) jdtNode);
case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
return convertVariableDeclarationExpression(
(org.eclipse.jdt.core.dom.VariableDeclarationExpression) jdtNode);
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
return convertVariableDeclarationFragment(
(org.eclipse.jdt.core.dom.VariableDeclarationFragment) jdtNode);
case ASTNode.VARIABLE_DECLARATION_STATEMENT:
return convertVariableDeclarationStatement(
(org.eclipse.jdt.core.dom.VariableDeclarationStatement) jdtNode);
case ASTNode.WHILE_STATEMENT:
return convertWhileStatement((org.eclipse.jdt.core.dom.WhileStatement) jdtNode);
// These nodes only appear in comments and J2ObjC doens't need any
// information from their subtree so we just convert them to TextElement.
case ASTNode.MEMBER_REF:
case ASTNode.METHOD_REF:
case ASTNode.METHOD_REF_PARAMETER:
return convertTextElement(jdtNode.toString());
case ASTNode.COMPILATION_UNIT:
throw new AssertionError(
"CompilationUnit must be converted using convertCompilationUnit()");
default:
throw new AssertionError("Unknown node type: " + jdtNode.getClass().getName());
}
}
private static TreeNode convertAbstractTypeDeclaration(
org.eclipse.jdt.core.dom.AbstractTypeDeclaration node, AbstractTypeDeclaration newNode) {
convertBodyDeclaration(node, newNode);
ITypeBinding typeBinding = node.resolveBinding();
Set<IMethodBinding> declaredInAst = new HashSet<>();
for (Object bodyDecl : node.bodyDeclarations()) {
if (bodyDecl instanceof org.eclipse.jdt.core.dom.MethodDeclaration) {
declaredInAst.add(((org.eclipse.jdt.core.dom.MethodDeclaration) bodyDecl).resolveBinding());
}
newNode.addBodyDeclaration((BodyDeclaration) convert(bodyDecl));
}
for (IMethodBinding method : typeBinding.getDeclaredMethods()) {
if (method.isConstructor() && method.getParameterTypes().length == 0
&& !declaredInAst.contains(method)) {
MethodDeclaration defaultConstructor =
new MethodDeclaration(BindingConverter.getExecutableElement(method))
.setBody(new Block());
addImplicitSuperCall(defaultConstructor);
newNode.addBodyDeclaration(0, defaultConstructor);
break;
}
}
return newNode
.setName((SimpleName) convert(node.getName()))
.setTypeElement(BindingConverter.getTypeElement(typeBinding));
}
private static TreeNode convertAnnotatableType(
org.eclipse.jdt.core.dom.AnnotatableType node, AnnotatableType newNode) {
if (node.getAST().apiLevel() == AST.JLS8) {
for (Object x : node.annotations()) {
newNode.addAnnotation((Annotation) convert(x));
}
}
return newNode;
}
private static TreeNode convertAnnotationTypeDeclaration(
org.eclipse.jdt.core.dom.AnnotationTypeDeclaration node) {
return convertAbstractTypeDeclaration(node, new AnnotationTypeDeclaration());
}
private static TreeNode convertAnnotationTypeMemberDeclaration(
org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration node) {
AnnotationTypeMemberDeclaration newNode = new AnnotationTypeMemberDeclaration();
convertBodyDeclaration(node, newNode);
return newNode
.setExecutableElement(BindingConverter.getExecutableElement(node.resolveBinding()))
.setDefault((Expression) convert(node.getDefault()));
}
private static TypeDeclaration convertAnonymousClassDeclaration(
org.eclipse.jdt.core.dom.AnonymousClassDeclaration node,
JdtExecutableElement constructorElem, IMethodBinding constructorBinding) {
TypeDeclaration typeDecl = (TypeDeclaration) new TypeDeclaration(
(TypeElement) BindingConverter.getElement(node.resolveBinding()))
.addBodyDeclaration(createAnonymousConstructor(constructorElem, constructorBinding))
.setPosition(getPosition(node));
for (Object bodyDecl : node.bodyDeclarations()) {
typeDecl.addBodyDeclaration((BodyDeclaration) convert(bodyDecl));
}
return typeDecl;
}
private static MethodDeclaration createAnonymousConstructor(
JdtExecutableElement constructorElem, IMethodBinding constructorBinding) {
MethodDeclaration constructor = new MethodDeclaration(constructorElem);
Block body = new Block();
constructor.setBody(body);
IMethodBinding superConstructorBinding = findSuperConstructor(constructorBinding);
ExecutablePair superConstructor = new ExecutablePair(
BindingConverter.getExecutableElement(superConstructorBinding),
BindingConverter.getType(superConstructorBinding));
SuperConstructorInvocation superCall = new SuperConstructorInvocation(superConstructor);
body.addStatement(superCall);
Iterator<? extends VariableElement> params = constructorElem.getParameters().iterator();
if (constructorElem.hasSuperOuter()) {
VariableElement param = params.next();
constructor.addParameter(new SingleVariableDeclaration(param));
superCall.setExpression(new SimpleName(param));
}
while (params.hasNext()) {
VariableElement param = params.next();
constructor.addParameter(new SingleVariableDeclaration(param));
superCall.addArgument(new SimpleName(param));
}
assert constructor.getParameters().size() == constructorElem.getParameters().size();
return constructor;
}
private static IMethodBinding findSuperConstructor(IMethodBinding constructor) {
ITypeBinding superClass = constructor.getDeclaringClass().getSuperclass();
for (IMethodBinding m : superClass.getDeclaredMethods()) {
if (m.isConstructor() && constructor.isSubsignature(m)) {
return m;
}
}
throw new AssertionError("could not find constructor");
}
private static TreeNode convertArrayAccess(org.eclipse.jdt.core.dom.ArrayAccess node) {
return new ArrayAccess()
.setArray((Expression) convert(node.getArray()))
.setIndex((Expression) convert(node.getIndex()));
}
private static TreeNode convertArrayCreation(org.eclipse.jdt.core.dom.ArrayCreation node) {
ArrayCreation newNode = new ArrayCreation();
convertExpression(node, newNode);
List<Expression> dimensions = new ArrayList<>();
for (Object dimension : node.dimensions()) {
dimensions.add((Expression) convert(dimension));
}
return newNode
.setType((ArrayType) convert(node.getType()))
.setDimensions(dimensions)
.setInitializer((ArrayInitializer) convert(node.getInitializer()));
}
private static TreeNode convertArrayInitializer(org.eclipse.jdt.core.dom.ArrayInitializer node) {
List<Expression> expressions = new ArrayList<>();
for (Object expression : node.expressions()) {
expressions.add((Expression) convert(expression));
}
ArrayInitializer newNode = new ArrayInitializer();
convertExpression(node, newNode);
return newNode
.setTypeMirror((JdtArrayType) BindingConverter.getType(node.resolveTypeBinding()))
.setExpressions(expressions);
}
private static TreeNode convertArrayType(org.eclipse.jdt.core.dom.ArrayType node) {
ArrayType newNode = new ArrayType();
convertType(node, newNode);
// This could also be implemented as an element type and dimensions for JLS8, but we mainly deal
// with ArrayTypes through the ArrayType(ITypeBinding) initializer, in the ArrayRewriter, for
// which we use ITypeBinding's componentType anyway.
Type componentType = (Type) Type.newType(
BindingConverter.getType(node.resolveBinding().getComponentType()));
return newNode.setComponentType(componentType);
}
private static TreeNode convertAssertStatement(org.eclipse.jdt.core.dom.AssertStatement node) {
return new AssertStatement()
.setExpression((Expression) convert(node.getExpression()))
.setMessage((Expression) convert(node.getMessage()));
}
private static TreeNode convertAssignment(org.eclipse.jdt.core.dom.Assignment node) {
Assignment newNode = new Assignment();
convertExpression(node, newNode);
return newNode
.setOperator(Assignment.Operator.fromJdtOperatorName(node.getOperator().toString()))
.setLeftHandSide((Expression) convert(node.getLeftHandSide()))
.setRightHandSide((Expression) convert(node.getRightHandSide()));
}
private static TreeNode convertBlock(org.eclipse.jdt.core.dom.Block node) {
Block newNode = new Block();
for (Object statement : node.statements()) {
newNode.addStatement((Statement) convert(statement));
}
return newNode;
}
private static TreeNode convertBodyDeclaration(
org.eclipse.jdt.core.dom.BodyDeclaration node, BodyDeclaration newNode) {
List<Annotation> annotations = new ArrayList<>();
for (Object modifier : node.modifiers()) {
if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) {
annotations.add((Annotation) convert(modifier));
}
}
return newNode
.setModifiers(node.getModifiers())
.setAnnotations(annotations)
.setJavadoc((Javadoc) convert(node.getJavadoc()));
}
private static TreeNode convertBooleanLiteral(org.eclipse.jdt.core.dom.BooleanLiteral node) {
return convertExpression(node, new BooleanLiteral(node.booleanValue(),
BindingConverter.getType(node.resolveTypeBinding())));
}
private static TreeNode convertBreakStatement(org.eclipse.jdt.core.dom.BreakStatement node) {
return new BreakStatement()
.setLabel((SimpleName) convert(node.getLabel()));
}
private static TreeNode convertCastExpression(org.eclipse.jdt.core.dom.CastExpression node) {
CastExpression newNode = new CastExpression();
convertExpression(node, newNode);
return newNode
.setType((Type) convert(node.getType()))
.setExpression((Expression) convert(node.getExpression()));
}
private static TreeNode convertCatchClause(org.eclipse.jdt.core.dom.CatchClause node) {
return new CatchClause()
.setBody((Block) convert(node.getBody()))
.setException((SingleVariableDeclaration) convert(node.getException()));
}
private static TreeNode convertCharacterLiteral(org.eclipse.jdt.core.dom.CharacterLiteral node) {
return convertExpression(node, new CharacterLiteral(node.charValue(),
BindingConverter.getType(node.resolveTypeBinding())));
}
private static TreeNode convertClassInstanceCreation(
org.eclipse.jdt.core.dom.ClassInstanceCreation node) {
ClassInstanceCreation newNode = new ClassInstanceCreation();
convertExpression(node, newNode);
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) TreeConverter.convert(argument));
}
IMethodBinding binding = node.resolveConstructorBinding();
JdtExecutableElement element =
(JdtExecutableElement) BindingConverter.getExecutableElement(binding);
JdtExecutableType type = BindingConverter.getType(binding);
newNode
.setExecutablePair(new ExecutablePair(element, type))
.setVarargsType(getVarargsType(binding, node.arguments()))
.setType((Type) TreeConverter.convert(node.getType()));
Expression expression = (Expression) TreeConverter.convert(node.getExpression());
org.eclipse.jdt.core.dom.AnonymousClassDeclaration anonymousClassDecl =
node.getAnonymousClassDeclaration();
if (anonymousClassDecl != null && expression != null) {
VariableElement superOuterParam = GeneratedVariableElement.newParameter(
"superOuter$", expression.getTypeMirror(), element);
element.setSuperOuterParam(superOuterParam);
type.setSuperOuterParamType(superOuterParam.asType());
newNode.addArgument(0, expression);
} else {
newNode.setExpression(expression);
}
if (anonymousClassDecl != null) {
newNode.setAnonymousClassDeclaration(convertAnonymousClassDeclaration(
anonymousClassDecl, element, binding));
}
return newNode;
}
private static TreeNode convertConditionalExpression(
org.eclipse.jdt.core.dom.ConditionalExpression node) {
return new ConditionalExpression()
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()))
.setExpression((Expression) convert(node.getExpression()))
.setThenExpression((Expression) convert(node.getThenExpression()))
.setElseExpression((Expression) convert(node.getElseExpression()));
}
private static TreeNode convertConstructorInvocation(
org.eclipse.jdt.core.dom.ConstructorInvocation node) {
IMethodBinding binding = node.resolveConstructorBinding();
ConstructorInvocation newNode = new ConstructorInvocation()
.setExecutablePair(new ExecutablePair(
BindingConverter.getExecutableElement(binding), BindingConverter.getType(binding)))
.setVarargsType(getVarargsType(binding, node.arguments()));
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) convert(argument));
}
return newNode;
}
private static TreeNode convertContinueStatement(
org.eclipse.jdt.core.dom.ContinueStatement node) {
return new ContinueStatement()
.setLabel((SimpleName) convert(node.getLabel()));
}
private static TreeNode convertCreationReference(
org.eclipse.jdt.core.dom.CreationReference node) {
CreationReference newNode = new CreationReference();
convertMethodReference(node, newNode, node.resolveMethodBinding(), false);
return newNode.
setType((Type) TreeConverter.convert(node.getType()));
}
private static TreeNode convertDimension(org.eclipse.jdt.core.dom.Dimension node) {
Dimension newNode = new Dimension();
for (Object x : node.annotations()) {
newNode.addAnnotation((Annotation) convert(x));
}
return newNode;
}
private static TreeNode convertDoStatement(org.eclipse.jdt.core.dom.DoStatement node) {
return new DoStatement()
.setExpression((Expression) convert(node.getExpression()))
.setBody((Statement) convert(node.getBody()));
}
private static TreeNode convertEnhancedForStatement(
org.eclipse.jdt.core.dom.EnhancedForStatement node) {
return new EnhancedForStatement()
.setParameter((SingleVariableDeclaration) convert(node.getParameter()))
.setExpression((Expression) convert(node.getExpression()))
.setBody((Statement) convert(node.getBody()));
}
private static TreeNode convertEnumConstantDeclaration(
org.eclipse.jdt.core.dom.EnumConstantDeclaration node) {
EnumConstantDeclaration newNode = new EnumConstantDeclaration();
convertBodyDeclaration(node, newNode);
IMethodBinding methodBinding = node.resolveConstructorBinding();
JdtExecutableElement element =
(JdtExecutableElement) BindingConverter.getExecutableElement(methodBinding);
newNode
.setVariableElement(BindingConverter.getVariableElement(node.resolveVariable()))
.setExecutablePair(new ExecutablePair(element, BindingConverter.getType(methodBinding)))
.setVarargsType(getVarargsType(methodBinding, node.arguments()));
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) convert(argument));
}
org.eclipse.jdt.core.dom.AnonymousClassDeclaration anonymousClassDecl =
node.getAnonymousClassDeclaration();
if (anonymousClassDecl != null) {
newNode.setAnonymousClassDeclaration(convertAnonymousClassDeclaration(
anonymousClassDecl, element, methodBinding));
}
return newNode;
}
private static TreeNode convertEnumDeclaration(org.eclipse.jdt.core.dom.EnumDeclaration node) {
EnumDeclaration newNode =
(EnumDeclaration) convertAbstractTypeDeclaration(node, new EnumDeclaration());
for (Object enumConstant : node.enumConstants()) {
newNode.addEnumConstant((EnumConstantDeclaration) convert(enumConstant));
}
return newNode;
}
private static TreeNode convertExpression(
org.eclipse.jdt.core.dom.Expression node, Expression newNode) {
return newNode.setConstantValue(node.resolveConstantExpressionValue());
}
private static TreeNode convertExpressionMethodReference(
org.eclipse.jdt.core.dom.ExpressionMethodReference node) {
IMethodBinding methodBinding = node.resolveMethodBinding();
ExpressionMethodReference newNode = new ExpressionMethodReference();
Expression expression = (Expression) convert(node.getExpression());
boolean consumesFirstParam = !BindingUtil.isStatic(methodBinding)
&& expression instanceof Name
&& !ElementUtil.isVariable(((Name) expression).getElement());
convertMethodReference(node, newNode, methodBinding, consumesFirstParam);
return newNode.setExpression(expression);
}
private static TreeNode convertExpressionStatement(
org.eclipse.jdt.core.dom.ExpressionStatement node) {
return new ExpressionStatement()
.setExpression((Expression) convert(node.getExpression()));
}
private static TreeNode convertFieldAccess(org.eclipse.jdt.core.dom.FieldAccess node) {
return new FieldAccess()
.setVariableElement(BindingConverter.getVariableElement(node.resolveFieldBinding()))
.setExpression((Expression) convert(node.getExpression()))
.setName((SimpleName) convert(node.getName()));
}
private static TreeNode convertFieldDeclaration(org.eclipse.jdt.core.dom.FieldDeclaration node) {
FieldDeclaration newNode = new FieldDeclaration();
convertBodyDeclaration(node, newNode);
for (Object fragment : node.fragments()) {
newNode.addFragment((VariableDeclarationFragment) convert(fragment));
}
return newNode;
}
private static TreeNode convertForStatement(org.eclipse.jdt.core.dom.ForStatement node) {
ForStatement newNode = new ForStatement();
for (Object initializer : node.initializers()) {
newNode.addInitializer((Expression) convert(initializer));
}
for (Object updater : node.updaters()) {
newNode.addUpdater((Expression) convert(updater));
}
return newNode
.setExpression((Expression) convert(node.getExpression()))
.setBody((Statement) convert(node.getBody()));
}
private static TreeNode convertFunctionalExpression(
org.eclipse.jdt.core.dom.Expression node, FunctionalExpression newNode) {
convertExpression(node, newNode);
ITypeBinding typeBinding = node.resolveTypeBinding();
newNode.setTypeMirror(BindingConverter.getType(typeBinding));
ASTNode parent = node.getParent();
// When a lambda or method reference is cast to an intersection type, the JDT does not provide
// all of the target types in the node's type binding, so we check for a parent CastExpression.
if (parent instanceof org.eclipse.jdt.core.dom.CastExpression) {
typeBinding = ((org.eclipse.jdt.core.dom.CastExpression) parent).resolveTypeBinding();
}
if (BindingUtil.isIntersectionType(typeBinding)) {
for (ITypeBinding i : typeBinding.getInterfaces()) {
newNode.addTargetType(BindingConverter.getType(i));
}
} else {
newNode.addTargetType(BindingConverter.getType(typeBinding));
}
return newNode;
}
private static TreeNode convertIfStatement(org.eclipse.jdt.core.dom.IfStatement node) {
return new IfStatement()
.setExpression((Expression) convert(node.getExpression()))
.setThenStatement((Statement) convert(node.getThenStatement()))
.setElseStatement((Statement) convert(node.getElseStatement()));
}
private static TreeNode convertInfixExpression(org.eclipse.jdt.core.dom.InfixExpression node) {
InfixExpression newNode = new InfixExpression();
convertExpression(node, newNode);
newNode
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()))
.setOperator(InfixExpression.Operator.parse(node.getOperator().toString()));
// The JDT parser apparently does not always take advantage of extended
// operands, resulting in potentially very deep trees that can overflow the
// stack. This code traverses the subtree non-recursively and merges all
// children that have the same operator into this node using extended
// operands.
List<StackState> stack = Lists.newArrayList();
stack.add(new StackState(node));
while (!stack.isEmpty()) {
StackState currentState = stack.get(stack.size() - 1);
org.eclipse.jdt.core.dom.Expression child = currentState.nextChild();
if (child == null) {
stack.remove(stack.size() - 1);
continue;
}
if (child instanceof org.eclipse.jdt.core.dom.InfixExpression) {
org.eclipse.jdt.core.dom.InfixExpression infixChild =
(org.eclipse.jdt.core.dom.InfixExpression) child;
if (infixChild.getOperator().equals(node.getOperator())) {
stack.add(new StackState(infixChild));
continue;
}
}
newNode.addOperand((Expression) TreeConverter.convert(child));
}
return newNode;
}
private static TreeNode convertInitializer(org.eclipse.jdt.core.dom.Initializer node) {
Initializer newNode = new Initializer();
convertBodyDeclaration(node, newNode);
return newNode
.setBody((Block) convert(node.getBody()));
}
private static TreeNode convertInstanceofExpression(
org.eclipse.jdt.core.dom.InstanceofExpression node) {
return new InstanceofExpression()
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()))
.setLeftOperand((Expression) convert(node.getLeftOperand()))
.setRightOperand((Type) convert(node.getRightOperand()));
}
private static TreeNode convertIntersectionType(org.eclipse.jdt.core.dom.IntersectionType node) {
TypeMirror type = BindingConverter.getType(node.resolveBinding());
IntersectionType newNode = new IntersectionType(type);
for (Object x : node.types()) {
newNode.addType((Type) convert(x));
}
return newNode;
}
private static TreeNode convertJavadoc(org.eclipse.jdt.core.dom.Javadoc node) {
Javadoc newNode = new Javadoc();
for (Object tag : node.tags()) {
newNode.addTag((TagElement) convert(tag));
}
return newNode;
}
private static TreeNode convertLabeledStatement(org.eclipse.jdt.core.dom.LabeledStatement node) {
return new LabeledStatement()
.setLabel((SimpleName) convert(node.getLabel()))
.setBody((Statement) convert(node.getBody()));
}
private static TreeNode convertLambdaExpression(org.eclipse.jdt.core.dom.LambdaExpression node) {
LambdaExpression newNode = new LambdaExpression();
convertFunctionalExpression(node, newNode);
for (Object x : node.parameters()) {
newNode.addParameter((VariableDeclaration) TreeConverter.convert(x));
}
return newNode.setBody(TreeConverter.convert(node.getBody()));
}
private static TreeNode convertAnnotation(org.eclipse.jdt.core.dom.Annotation node,
Annotation newNode) {
convertExpression(node, newNode);
return newNode
.setAnnotationMirror(new JdtAnnotationMirror(node.resolveAnnotationBinding()))
.setTypeName((Name) convert(node.getTypeName()));
}
private static TreeNode convertMarkerAnnotation(org.eclipse.jdt.core.dom.MarkerAnnotation node) {
Annotation newNode = null;
if (node.getTypeName().getFullyQualifiedName().equals(Property.class.getSimpleName())) {
newNode = new PropertyAnnotation();
for (String attr : BindingUtil.parseAttributeString(node.resolveAnnotationBinding())) {
((PropertyAnnotation) newNode).addAttribute(attr);
}
} else {
newNode = new MarkerAnnotation();
}
return convertAnnotation(node, newNode);
}
private static TreeNode convertMemberValuePair(org.eclipse.jdt.core.dom.MemberValuePair node) {
return new MemberValuePair()
.setName((SimpleName) convert(node.getName()))
.setValue((Expression) convert(node.getValue()));
}
private static TreeNode convertMethodDeclaration(
org.eclipse.jdt.core.dom.MethodDeclaration node) {
MethodDeclaration newNode = new MethodDeclaration();
convertBodyDeclaration(node, newNode);
for (Object param : node.parameters()) {
newNode.addParameter((SingleVariableDeclaration) TreeConverter.convert(param));
}
newNode
.setIsConstructor(node.isConstructor())
.setExecutableElement(BindingConverter.getExecutableElement(node.resolveBinding()))
.setBody((Block) TreeConverter.convert(node.getBody()));
maybeAddImplicitSuperCall(newNode);
return newNode;
}
private static TreeNode convertMethodInvocation(org.eclipse.jdt.core.dom.MethodInvocation node) {
MethodInvocation newNode = new MethodInvocation();
convertExpression(node, newNode);
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) TreeConverter.convert(argument));
}
IMethodBinding methodBinding = node.resolveMethodBinding();
return newNode
.setExecutablePair(new ExecutablePair(
BindingConverter.getExecutableElement(methodBinding),
BindingConverter.getType(methodBinding)))
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()))
.setExpression((Expression) TreeConverter.convert(node.getExpression()))
.setVarargsType(getVarargsType(methodBinding, node.arguments()));
}
private static TreeNode convertMethodReference(
org.eclipse.jdt.core.dom.MethodReference node, MethodReference newNode,
IMethodBinding binding, boolean consumeFirstParam) {
convertFunctionalExpression(node, newNode);
for (Object x : node.typeArguments()) {
newNode.addTypeArgument((Type) TreeConverter.convert(x));
}
IMethodBinding functionalInterface = getFunctionalInterface(node.resolveTypeBinding());
return newNode
.setExecutableElement(BindingConverter.getExecutableElement(binding))
.setVarargsType(getVarargsType(binding, functionalInterface, consumeFirstParam));
}
private static TreeNode convertName(org.eclipse.jdt.core.dom.Name node, Name newNode) {
convertExpression(node, newNode);
return newNode.setElement(BindingConverter.getElement(node.resolveBinding()));
}
private static TreeNode convertNameQualifiedType(
org.eclipse.jdt.core.dom.NameQualifiedType node) {
TypeMirror type = BindingConverter.getType(node.resolveBinding());
return ((NameQualifiedType) convertAnnotatableType(node, new NameQualifiedType(type)))
.setName((SimpleName) convert(node.getName()))
.setQualifier((Name) convert(node.getQualifier()));
}
private static TreeNode convertNormalAnnotation(org.eclipse.jdt.core.dom.NormalAnnotation node) {
NormalAnnotation newNode = new NormalAnnotation();
for (Object value : node.values()) {
newNode.addValue((MemberValuePair) convert(value));
}
return convertAnnotation(node, newNode);
}
private static TreeNode convertNumberLiteral(org.eclipse.jdt.core.dom.NumberLiteral node) {
Object constantValue = node.resolveConstantExpressionValue();
assert constantValue instanceof Number;
Number value = (Number) constantValue;
ITypeBinding typeBinding = node.resolveTypeBinding();
return convertExpression(node, new NumberLiteral(value, BindingConverter.getType(typeBinding))
.setToken(node.getToken()));
}
private static TreeNode convertPackageDeclaration(
org.eclipse.jdt.core.dom.PackageDeclaration node) {
PackageDeclaration newNode = new PackageDeclaration()
.setName((Name) convert(node.getName()))
.setPackageElement((PackageElement) BindingConverter.getPackageElement(node))
.setJavadoc((Javadoc) convert(node.getJavadoc()));
for (Object modifier : node.annotations()) {
newNode.addAnnotation((Annotation) TreeConverter.convert(modifier));
}
return newNode;
}
private static TreeNode convertParameterizedType(
org.eclipse.jdt.core.dom.ParameterizedType node) {
return ((ParameterizedType) convertType(node, new ParameterizedType()))
.setType((Type) TreeConverter.convert(node.getType()));
}
private static TreeNode convertParenthesizedExpression(
org.eclipse.jdt.core.dom.ParenthesizedExpression node) {
ParenthesizedExpression newNode = new ParenthesizedExpression();
convertExpression(node, newNode);
return newNode
.setExpression((Expression) TreeConverter.convert(node.getExpression()));
}
private static TreeNode convertPostfixExpression(
org.eclipse.jdt.core.dom.PostfixExpression node) {
PostfixExpression newNode = new PostfixExpression();
convertExpression(node, newNode);
return newNode
.setOperator(PostfixExpression.Operator.parse(node.getOperator().toString()))
.setOperand((Expression) TreeConverter.convert(node.getOperand()));
}
private static TreeNode convertPrefixExpression(
org.eclipse.jdt.core.dom.PrefixExpression node) {
PrefixExpression newNode = new PrefixExpression();
convertExpression(node, newNode);
return newNode
.setOperator(PrefixExpression.Operator.parse(node.getOperator().toString()))
.setOperand((Expression) TreeConverter.convert(node.getOperand()))
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()));
}
private static TreeNode convertPrimitiveType(org.eclipse.jdt.core.dom.PrimitiveType node) {
TypeMirror type = BindingConverter.getType(node.resolveBinding());
return convertAnnotatableType(node, new PrimitiveType(type));
}
private static TreeNode convertQualifiedName(org.eclipse.jdt.core.dom.QualifiedName node) {
QualifiedName newNode = new QualifiedName();
convertName(node, newNode);
return newNode
.setQualifier((Name) TreeConverter.convert(node.getQualifier()))
.setName((SimpleName) TreeConverter.convert(node.getName()));
}
private static TreeNode convertQualifiedType(org.eclipse.jdt.core.dom.QualifiedType node) {
TypeMirror type = BindingConverter.getType(node.resolveBinding());
return convertAnnotatableType(node, new QualifiedType(type));
}
private static TreeNode convertReturnStatement(org.eclipse.jdt.core.dom.ReturnStatement node) {
return new ReturnStatement()
.setExpression((Expression) TreeConverter.convert(node.getExpression()));
}
private static TreeNode convertSimpleName(org.eclipse.jdt.core.dom.SimpleName node) {
SimpleName newNode = new SimpleName();
convertName(node, newNode);
boolean isConstructor = node.resolveBinding() instanceof IMethodBinding
&& ((IMethodBinding) node.resolveBinding()).isConstructor();
return newNode
.setIdentifier(isConstructor ? "<init>" : node.getIdentifier())
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()));
}
private static TreeNode convertSimpleType(org.eclipse.jdt.core.dom.SimpleType node) {
TypeMirror type = BindingConverter.getType(node.resolveBinding());
return convertAnnotatableType(node, new SimpleType(type));
}
private static TreeNode convertSingleMemberAnnotation(
org.eclipse.jdt.core.dom.SingleMemberAnnotation node) {
Annotation newNode = null;
if (node.getTypeName().getFullyQualifiedName().equals(Property.class.getSimpleName())) {
newNode = new PropertyAnnotation();
for (String attr : BindingUtil.parseAttributeString(node.resolveAnnotationBinding())) {
((PropertyAnnotation) newNode).addAttribute(attr);
}
} else {
newNode = new SingleMemberAnnotation()
.setValue((Expression) convert(node.getValue()));
}
return convertAnnotation(node, newNode);
}
private static TreeNode convertSingleVariableDeclaration(
org.eclipse.jdt.core.dom.SingleVariableDeclaration node) {
SingleVariableDeclaration newNode = new SingleVariableDeclaration();
convertVariableDeclaration(node, newNode);
for (Object modifier : node.modifiers()) {
if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) {
newNode.addAnnotation((Annotation) TreeConverter.convert(modifier));
}
}
return newNode
.setType((Type) TreeConverter.convert(node.getType()))
.setIsVarargs(node.isVarargs());
}
private static TreeNode convertStringLiteral(org.eclipse.jdt.core.dom.StringLiteral node) {
StringLiteral newNode = new StringLiteral();
convertExpression(node, newNode);
return newNode
.setLiteralValue(node.getLiteralValue())
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()));
}
private static TreeNode convertSuperConstructorInvocation(
org.eclipse.jdt.core.dom.SuperConstructorInvocation node) {
IMethodBinding binding = node.resolveConstructorBinding();
SuperConstructorInvocation newNode = new SuperConstructorInvocation()
.setExecutablePair(new ExecutablePair(
BindingConverter.getExecutableElement(binding), BindingConverter.getType(binding)))
.setVarargsType(getVarargsType(binding, node.arguments()));
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) convert(argument));
}
return newNode
.setExpression((Expression) TreeConverter.convert(node.getExpression()));
}
private static TreeNode convertSuperFieldAccess(org.eclipse.jdt.core.dom.SuperFieldAccess node) {
return new SuperFieldAccess()
.setVariableElement(BindingConverter.getVariableElement(node.resolveFieldBinding()))
.setQualifier((Name) convert(node.getQualifier()))
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()));
}
private static TreeNode convertSuperMethodReference(
org.eclipse.jdt.core.dom.SuperMethodReference node) {
SuperMethodReference newNode = new SuperMethodReference();
convertMethodReference(node, newNode, node.resolveMethodBinding(), false);
return newNode
.setQualifier((Name) TreeConverter.convert(node.getQualifier()));
}
private static TreeNode convertSwitchCase(org.eclipse.jdt.core.dom.SwitchCase node) {
return new SwitchCase()
.setExpression((Expression) TreeConverter.convert(node.getExpression()))
.setIsDefault(node.isDefault());
}
private static TreeNode convertSwitchStatement(org.eclipse.jdt.core.dom.SwitchStatement node) {
SwitchStatement newNode = new SwitchStatement()
.setExpression((Expression) TreeConverter.convert(node.getExpression()));
for (Object statement : node.statements()) {
newNode.addStatement((Statement) TreeConverter.convert(statement));
}
return newNode;
}
private static TreeNode convertSynchronizedStatement(
org.eclipse.jdt.core.dom.SynchronizedStatement node) {
return new SynchronizedStatement()
.setExpression((Expression) TreeConverter.convert(node.getExpression()))
.setBody((Block) TreeConverter.convert(node.getBody()));
}
private static TreeNode convertSuperMethodInvocation(
org.eclipse.jdt.core.dom.SuperMethodInvocation node) {
SuperMethodInvocation newNode = new SuperMethodInvocation();
convertExpression(node, newNode);
for (Object argument : node.arguments()) {
newNode.addArgument((Expression) TreeConverter.convert(argument));
}
IMethodBinding methodBinding = node.resolveMethodBinding();
return newNode
.setExecutablePair(new ExecutablePair(
BindingConverter.getExecutableElement(methodBinding),
BindingConverter.getType(methodBinding)))
.setVarargsType(getVarargsType(methodBinding, node.arguments()))
.setQualifier((Name) TreeConverter.convert(node.getQualifier()));
}
private static TreeNode convertTagElement(org.eclipse.jdt.core.dom.TagElement node) {
TagElement newNode = new TagElement()
.setTagKind(TagKind.parse(node.getTagName()));
for (Object fragment : node.fragments()) {
newNode.addFragment(TreeConverter.convert(fragment));
}
return newNode;
}
private static TreeNode convertTextElement(String text) {
return new TextElement().setText(text);
}
private static TreeNode convertThisExpression(org.eclipse.jdt.core.dom.ThisExpression node) {
ThisExpression newNode = new ThisExpression();
convertExpression(node, newNode);
return newNode
.setTypeMirror(BindingConverter.getType(node.resolveTypeBinding()))
.setQualifier((Name) TreeConverter.convert(node.getQualifier()));
}
private static TreeNode convertThrowStatement(org.eclipse.jdt.core.dom.ThrowStatement node) {
return new ThrowStatement()
.setExpression((Expression) TreeConverter.convert(node.getExpression()));
}
private static TreeNode convertTryStatement(org.eclipse.jdt.core.dom.TryStatement node) {
TryStatement newNode = new TryStatement()
.setBody((Block) TreeConverter.convert(node.getBody()))
.setFinally((Block) TreeConverter.convert(node.getFinally()));
for (Object resource : node.resources()) {
newNode.addResource((VariableDeclarationExpression) TreeConverter.convert(resource));
}
for (Object catchClause : node.catchClauses()) {
newNode.addCatchClause((CatchClause) TreeConverter.convert(catchClause));
}
return newNode;
}
private static TreeNode convertType(
org.eclipse.jdt.core.dom.Type node, Type newNode) {
return newNode.setTypeMirror(BindingConverter.getType(node.resolveBinding()));
}
private static TreeNode convertTypeDeclaration(org.eclipse.jdt.core.dom.TypeDeclaration node) {
TypeDeclaration newNode =
(TypeDeclaration) convertAbstractTypeDeclaration(node, new TypeDeclaration());
newNode.setInterface(node.isInterface());
return newNode;
}
private static TreeNode convertTypeDeclarationStatement(
org.eclipse.jdt.core.dom.TypeDeclarationStatement node) {
return new TypeDeclarationStatement()
.setDeclaration((AbstractTypeDeclaration) TreeConverter.convert(node.getDeclaration()));
}
private static TreeNode convertTypeLiteral(org.eclipse.jdt.core.dom.TypeLiteral node) {
TypeLiteral newNode = new TypeLiteral(BindingConverter.getType(node.resolveTypeBinding()));
convertExpression(node, newNode);
return newNode
.setType((Type) TreeConverter.convert(node.getType()));
}
private static TreeNode convertTypeMethodReference(
org.eclipse.jdt.core.dom.TypeMethodReference node) {
TypeMethodReference newNode = new TypeMethodReference();
IMethodBinding methodBinding = node.resolveMethodBinding();
if (node.getType().resolveBinding().isArray()) {
// JDT does not provide the correct method on array types, so we find it from
// java.lang.Object.
IMethodBinding functionalInterface = getFunctionalInterface(node.resolveTypeBinding());
methodBinding = getObjectMethod(
node.getAST(), node.getName().getIdentifier(),
functionalInterface.getParameterTypes().length - 1);
}
convertMethodReference(node, newNode, methodBinding, !BindingUtil.isStatic(methodBinding));
return newNode
.setType((Type) TreeConverter.convert(node.getType()));
}
private static IMethodBinding getObjectMethod(AST ast, String name, int numParams) {
ITypeBinding objectType = ast.resolveWellKnownType("java.lang.Object");
for (IMethodBinding method : objectType.getDeclaredMethods()) {
if (method.getName().equals(name) && method.getParameterTypes().length == numParams) {
return method;
}
}
throw new AssertionError("Can't find method element for method: " + name);
}
private static TreeNode convertUnionType(org.eclipse.jdt.core.dom.UnionType node) {
UnionType newNode = new UnionType();
convertType(node, newNode);
for (Object type : node.types()) {
newNode.addType((Type) TreeConverter.convert(type));
}
return newNode;
}
private static TreeNode convertVariableDeclaration(
org.eclipse.jdt.core.dom.VariableDeclaration node, VariableDeclaration newNode) {
return newNode
.setVariableElement(BindingConverter.getVariableElement(node.resolveBinding()))
.setExtraDimensions(node.getExtraDimensions())
.setInitializer((Expression) TreeConverter.convert(node.getInitializer()));
}
private static TreeNode convertVariableDeclarationExpression(
org.eclipse.jdt.core.dom.VariableDeclarationExpression node) {
VariableDeclarationExpression newNode = new VariableDeclarationExpression();
convertExpression(node, newNode);
for (Object fragment : node.fragments()) {
newNode.addFragment((VariableDeclarationFragment) TreeConverter.convert(fragment));
}
return newNode
.setType((Type) TreeConverter.convert(node.getType()));
}
private static TreeNode convertVariableDeclarationFragment(
org.eclipse.jdt.core.dom.VariableDeclarationFragment node) {
return convertVariableDeclaration(node, new VariableDeclarationFragment());
}
private static TreeNode convertVariableDeclarationStatement(
org.eclipse.jdt.core.dom.VariableDeclarationStatement node) {
VariableDeclarationStatement newNode = new VariableDeclarationStatement();
for (Object modifier : node.modifiers()) {
if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) {
newNode.addAnnotation((Annotation) TreeConverter.convert(modifier));
}
}
for (Object fragment : node.fragments()) {
newNode.addFragment((VariableDeclarationFragment) TreeConverter.convert(fragment));
}
return newNode;
}
private static TreeNode convertWhileStatement(org.eclipse.jdt.core.dom.WhileStatement node) {
return new WhileStatement()
.setExpression((Expression) convert(node.getExpression()))
.setBody((Statement) convert(node.getBody()));
}
private static void maybeAddImplicitSuperCall(MethodDeclaration node) {
if (needsImplicitSuperCall(node)) {
addImplicitSuperCall(node);
}
}
private static boolean needsImplicitSuperCall(MethodDeclaration node) {
ExecutableElement method = node.getExecutableElement();
if (!ElementUtil.isConstructor(method)) {
return false;
}
TypeMirror superType = ElementUtil.getDeclaringClass(method).getSuperclass();
if (TypeUtil.isNone(superType)) { // java.lang.Object supertype is null.
return false;
}
List<Statement> stmts = node.getBody().getStatements();
if (stmts.isEmpty()) {
return true;
}
Statement firstStmt = stmts.get(0);
return !(firstStmt instanceof SuperConstructorInvocation
|| firstStmt instanceof ConstructorInvocation);
}
private static void addImplicitSuperCall(MethodDeclaration node) {
ExecutableElement method = node.getExecutableElement();
DeclaredType superType = (DeclaredType) ElementUtil.getDeclaringClass(method).getSuperclass();
TypeElement superClass = TypeUtil.asTypeElement(superType);
ExecutableElement superConstructor = findDefaultConstructorElement(superClass);
SuperConstructorInvocation invocation = new SuperConstructorInvocation(new ExecutablePair(
superConstructor,
(ExecutableType) JdtTypes.asMemberOfInternal(superType, superConstructor)))
.setVarargsType(getVarargsType(
BindingConverter.unwrapExecutableElement(superConstructor), Collections.emptyList()));
node.getBody().addStatement(0, invocation);
}
private static ExecutableElement findDefaultConstructorElement(TypeElement type) {
if (ElementUtil.getQualifiedName(type).equals("java.lang.Enum")) {
// Enums are a special case where instead of a default no-param constructor it has a single
// two param constructor that accepts the implicit name and ordinal values.
ExecutableElement enumConstructor =
Iterables.getFirst(ElementUtil.getConstructors(type), null);
assert enumConstructor != null && enumConstructor.getParameters().size() == 2;
return enumConstructor;
}
ExecutableElement result = null;
for (ExecutableElement c : ElementUtil.getConstructors(type)) {
// Search for a non-varargs match.
if (c.getParameters().isEmpty()) {
return c;
// Search for a varargs match. Choose the most specific. (JLS 15.12.2.5)
} else if (c.isVarArgs() && c.getParameters().size() == 1
&& (result == null || isAssignable(
c.getParameters().get(0).asType(), result.getParameters().get(0).asType()))) {
result = c;
}
}
assert result != null : "Couldn't find default constructor for " + type;
return result;
}
private static boolean isAssignable(TypeMirror t1, TypeMirror t2) {
return BindingConverter.unwrapTypeMirrorIntoTypeBinding(t1).isAssignmentCompatible(
BindingConverter.unwrapTypeMirrorIntoTypeBinding(t2));
}
private static IMethodBinding getFunctionalInterface(ITypeBinding type) {
if (BindingUtil.isIntersectionType(type)) {
for (ITypeBinding i : type.getInterfaces()) {
IMethodBinding functionalInterface = i.getFunctionalInterfaceMethod();
if (functionalInterface != null) {
return functionalInterface;
}
}
}
return type.getFunctionalInterfaceMethod();
}
// Gets the varargs type for a MethodReference node.
private static TypeMirror getVarargsType(
IMethodBinding method, IMethodBinding functionalInterface, boolean consumeFirstParam) {
if (method == null) { // Only possible for an array creation reference.
return null;
}
ITypeBinding[] argTypes = functionalInterface.getParameterTypes();
int numArgs = argTypes.length - (consumeFirstParam ? 1 : 0);
ITypeBinding lastArgType = argTypes.length > 0 ? argTypes[argTypes.length - 1] : null;
return getVarargsType(method, numArgs, lastArgType);
}
// Gets the varargs type for an invocation node.
@SuppressWarnings("unchecked")
private static TypeMirror getVarargsType(IMethodBinding method, List args) {
ITypeBinding lastArgType = null;
if (!args.isEmpty()) {
org.eclipse.jdt.core.dom.Expression lastArg =
(org.eclipse.jdt.core.dom.Expression) args.get(args.size() - 1);
lastArgType = lastArg.resolveTypeBinding();
// Special case: check for a clone method invocation, since clone()'s return
// type is declared as Object but it always returns the caller's type.
if (lastArg instanceof org.eclipse.jdt.core.dom.MethodInvocation) {
org.eclipse.jdt.core.dom.MethodInvocation invocation =
(org.eclipse.jdt.core.dom.MethodInvocation) lastArg;
if (invocation.resolveMethodBinding().getName().equals("clone")
&& invocation.arguments().isEmpty()) {
lastArgType = invocation.getExpression().resolveTypeBinding();
}
}
}
return getVarargsType(method, args.size(), lastArgType);
}
private static TypeMirror getVarargsType(
IMethodBinding method, int numArgs, ITypeBinding lastArgType) {
if (!method.isVarargs()) {
return null;
}
ITypeBinding[] paramTypes = method.getParameterTypes();
ITypeBinding varargType = paramTypes[paramTypes.length - 1];
assert varargType.isArray();
int varargsSize = numArgs - paramTypes.length + 1;
if (varargsSize == 1) {
if (lastArgType.isAssignmentCompatible(varargType)) {
// Last argument is already an array.
return null;
}
}
return BindingConverter.getType(varargType.getComponentType());
}
// Helper class for convertInfixExpression().
private static class StackState {
private final org.eclipse.jdt.core.dom.InfixExpression expression;
private int nextChild = -2;
private StackState(org.eclipse.jdt.core.dom.InfixExpression expr) {
expression = expr;
}
private org.eclipse.jdt.core.dom.Expression nextChild() {
int childIdx = nextChild++;
if (childIdx == -2) {
return expression.getLeftOperand();
} else if (childIdx == -1) {
return expression.getRightOperand();
} else if (childIdx < expression.extendedOperands().size()) {
return (org.eclipse.jdt.core.dom.Expression) expression.extendedOperands().get(childIdx);
} else {
return null;
}
}
}
}